import { Injectable, BadRequestException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, Between, MoreThanOrEqual } from 'typeorm';
import { Restaurant } from '../../entities/restaurant.entity';
import { DrawHistory } from '../../entities/draw-history.entity';
import { RestaurantMark } from '../../entities/restaurant-mark.entity';
import { DrawFilterDto, QueryDrawHistoryDto } from './dto';
import {
  DrawResponse,
  DrawStats,
  RestaurantDrawCount,
} from '../../common/types/response.types';
import { PaginatedResponse } from '../../common/interfaces/api-response.interface';

@Injectable()
export class DrawService {
  constructor(
    @InjectRepository(Restaurant)
    private readonly restaurantRepository: Repository<Restaurant>,
    @InjectRepository(DrawHistory)
    private readonly drawHistoryRepository: Repository<DrawHistory>,
    @InjectRepository(RestaurantMark)
    private readonly restaurantMarkRepository: Repository<RestaurantMark>,
  ) {}

  // 获取符合条件的餐厅
  async getEligibleRestaurants(filters?: DrawFilterDto): Promise<Restaurant[]> {
    const queryBuilder =
      this.restaurantRepository.createQueryBuilder('restaurant');

    // 按分类筛选
    if (filters?.categories && filters.categories.length > 0) {
      queryBuilder.andWhere('restaurant.category IN (:...categories)', {
        categories: filters.categories,
      });
    }

    // 排除已标记的餐厅
    if (filters?.excludeMarked) {
      const now = new Date();
      const markedRestaurantIds = await this.restaurantMarkRepository
        .createQueryBuilder('mark')
        .select('mark.restaurant_id')
        .where('mark.expires_at > :now', { now })
        .getRawMany()
        .then((results: { restaurant_id: string }[]) =>
          results.map((r) => r.restaurant_id),
        );

      if (markedRestaurantIds.length > 0) {
        queryBuilder.andWhere('restaurant.id NOT IN (:...markedIds)', {
          markedIds: markedRestaurantIds,
        });
      }
    }

    // 根据频率规则筛选
    const now = new Date();
    const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
    const weekStart = new Date(today);
    weekStart.setDate(today.getDate() - today.getDay());
    const monthStart = new Date(now.getFullYear(), now.getMonth(), 1);

    // 获取今天、本周、本月已抽过的餐厅ID
    const [todayDrawn, weekDrawn, monthDrawn] = await Promise.all([
      this.getDrawnRestaurantIds(today),
      this.getDrawnRestaurantIds(weekStart),
      this.getDrawnRestaurantIds(monthStart),
    ]);

    // 应用频率规则
    queryBuilder.andWhere(
      `(
        (restaurant.frequency_rule = 'daily' AND restaurant.id NOT IN (:...todayDrawn)) OR
        (restaurant.frequency_rule = 'weekly' AND restaurant.id NOT IN (:...weekDrawn)) OR
        (restaurant.frequency_rule = 'monthly' AND restaurant.id NOT IN (:...monthDrawn))
      )`,
      {
        todayDrawn: todayDrawn.length ? todayDrawn : [''],
        weekDrawn: weekDrawn.length ? weekDrawn : [''],
        monthDrawn: monthDrawn.length ? monthDrawn : [''],
      },
    );

    return queryBuilder.getMany();
  }

  // 开始抽签
  async startDraw(filters?: DrawFilterDto): Promise<DrawResponse> {
    const eligibleRestaurants = await this.getEligibleRestaurants(filters);

    if (eligibleRestaurants.length === 0) {
      throw new BadRequestException('没有符合条件的餐厅可以抽签');
    }

    // 随机选择一个餐厅
    const randomIndex = Math.floor(Math.random() * eligibleRestaurants.length);
    const selectedRestaurant = eligibleRestaurants[randomIndex];

    // 记录抽签历史
    const drawHistory = this.drawHistoryRepository.create({
      restaurant_id: selectedRestaurant.id,
      restaurant_name: selectedRestaurant.name,
      restaurant_category: selectedRestaurant.category,
      draw_time: new Date(),
    });
    await this.drawHistoryRepository.save(drawHistory);

    return {
      restaurant: selectedRestaurant,
      drawTime: drawHistory.draw_time.toISOString(),
      eligibleCount: eligibleRestaurants.length,
    };
  }

  // 重新抽签
  async redraw(filters?: DrawFilterDto): Promise<DrawResponse> {
    return this.startDraw(filters);
  }

  // 获取抽签历史
  async getDrawHistory(
    query: QueryDrawHistoryDto,
  ): Promise<PaginatedResponse<DrawHistory>> {
    const { page = 1, pageSize = 10, startDate, endDate } = query;
    const skip = (page - 1) * pageSize;

    const queryBuilder = this.drawHistoryRepository.createQueryBuilder('draw');

    if (startDate && endDate) {
      queryBuilder.andWhere('draw.draw_time BETWEEN :startDate AND :endDate', {
        startDate,
        endDate,
      });
    }

    queryBuilder.orderBy('draw.draw_time', 'DESC').skip(skip).take(pageSize);

    const [data, total] = await queryBuilder.getManyAndCount();
    const totalPages = Math.ceil(total / pageSize);

    return {
      data,
      total,
      page,
      pageSize,
      totalPages,
    };
  }

  // 获取最近抽签历史
  async getRecentDrawHistory(limit: number = 10): Promise<DrawHistory[]> {
    return this.drawHistoryRepository.find({
      order: { draw_time: 'DESC' },
      take: limit,
    });
  }

  // 获取今天抽签历史
  async getTodayDrawHistory(): Promise<DrawHistory[]> {
    const today = new Date();
    const startOfDay = new Date(
      today.getFullYear(),
      today.getMonth(),
      today.getDate(),
    );
    const endOfDay = new Date(startOfDay);
    endOfDay.setDate(endOfDay.getDate() + 1);

    return this.drawHistoryRepository.find({
      where: {
        draw_time: Between(startOfDay, endOfDay),
      },
      order: { draw_time: 'DESC' },
    });
  }

  // 获取本周抽签历史
  async getWeekDrawHistory(): Promise<DrawHistory[]> {
    const now = new Date();
    const weekStart = new Date(now);
    weekStart.setDate(now.getDate() - now.getDay());
    weekStart.setHours(0, 0, 0, 0);

    return this.drawHistoryRepository.find({
      where: {
        draw_time: MoreThanOrEqual(weekStart),
      },
      order: { draw_time: 'DESC' },
    });
  }

  // 获取本月抽签历史
  async getMonthDrawHistory(): Promise<DrawHistory[]> {
    const now = new Date();
    const monthStart = new Date(now.getFullYear(), now.getMonth(), 1);

    return this.drawHistoryRepository.find({
      where: {
        draw_time: MoreThanOrEqual(monthStart),
      },
      order: { draw_time: 'DESC' },
    });
  }

  // 删除抽签历史
  async deleteDrawHistory(id: string): Promise<void> {
    await this.drawHistoryRepository.delete(id);
  }

  // 清空抽签历史
  async clearDrawHistory(): Promise<void> {
    const result = await this.drawHistoryRepository.clear();
    console.log('清空抽签历史结果:', result);

    // 验证是否真的清空了
    const count = await this.drawHistoryRepository.count();
    console.log('清空后剩余记录数:', count);

    if (count > 0) {
      throw new Error(`清空失败，仍有 ${count} 条记录`);
    }
  }

  // 获取抽签统计
  async getDrawStats(): Promise<DrawStats> {
    const totalDraws = await this.drawHistoryRepository.count();
    const todayDraws = (await this.getTodayDrawHistory()).length;
    const weekDraws = (await this.getWeekDrawHistory()).length;
    const monthDraws = (await this.getMonthDrawHistory()).length;

    // 获取最受欢迎的餐厅
    const favoriteResult: { name: string; count: string } | undefined =
      await this.drawHistoryRepository
        .createQueryBuilder('draw')
        .select('draw.restaurant_name', 'name')
        .addSelect('COUNT(*)', 'count')
        .groupBy('draw.restaurant_name')
        .orderBy('count', 'DESC')
        .limit(1)
        .getRawOne();

    return {
      totalDraws,
      todayDraws,
      weekDraws,
      monthDraws,
      favoriteRestaurant: favoriteResult
        ? {
            name: favoriteResult.name,
            count: parseInt(favoriteResult.count),
          }
        : undefined,
    };
  }

  // 获取餐厅抽签次数统计
  async getRestaurantDrawCounts(
    startDate?: string,
    endDate?: string,
    limit?: number,
  ): Promise<RestaurantDrawCount[]> {
    const queryBuilder = this.drawHistoryRepository
      .createQueryBuilder('draw')
      .leftJoinAndSelect('draw.restaurant', 'restaurant')
      .select('restaurant')
      .addSelect('COUNT(draw.id)', 'count')
      .groupBy('restaurant.id');

    if (startDate && endDate) {
      queryBuilder.andWhere('draw.draw_time BETWEEN :startDate AND :endDate', {
        startDate,
        endDate,
      });
    }

    queryBuilder.orderBy('count', 'DESC');

    if (limit) {
      queryBuilder.limit(limit);
    }

    const results = await queryBuilder.getRawAndEntities();

    return results.entities.map((drawHistory, index) => ({
      restaurant: drawHistory.restaurant,
      count: parseInt((results.raw[index] as { count: string }).count),
    }));
  }

  // 辅助方法：获取指定日期之后已抽过的餐厅ID
  private async getDrawnRestaurantIds(fromDate: Date): Promise<string[]> {
    const results = await this.drawHistoryRepository
      .createQueryBuilder('draw')
      .select('DISTINCT draw.restaurant_id', 'restaurant_id')
      .where('draw.draw_time >= :fromDate', { fromDate })
      .getRawMany();

    return results.map((r: { restaurant_id: string }) => r.restaurant_id);
  }
}
